package com.dingding.order.core.distance.biz.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.http.HttpStatus;
import org.apache.log4j.Logger;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.dingding.common.core.base.daox.ICriteriaBaseDao;
import com.dingding.common.core.base.dto.ResponseEntity;
import com.dingding.common.core.beans.StagePriceCity;
import com.dingding.common.core.beans.special.SpecialStageprice;
import com.dingding.common.core.util.dto.CalculatDistanceDTO;
import com.dingding.order.core.distance.biz.ICalculateDistanceService;
import com.dingding.order.core.distance.biz.abstracts.AbstractCalculatDistance;
import com.dingding.order.core.distance.dao.IStagePriceCityDao;
import com.dingding.order.core.distance.dao.IStagePriceDao;
import com.dingding.order.dto.distance.ReqCalculateDistanceDTO;
import com.dingding.order.dto.distance.ReqSpecialCalculateDistance;
import com.dingding.order.dto.distance.ResSpecialCalculateDistance;

/**
 * 
 * @ClassName: SpecialCalculateDistanceServiceImpl 
 * @Description: 专车计算距离价格
 * @author YHQ
 * @date 2016年8月23日 上午11:12:35
 * @since V2.4.0 
 * 
 */
@Component("specialCalculateDistanceService")
public class SpecialCalculateDistanceServiceImpl
		extends AbstractCalculatDistance<ResSpecialCalculateDistance, ReqSpecialCalculateDistance>
		implements ICalculateDistanceService {

	private static Logger log = Logger.getLogger(SpecialCalculateDistanceServiceImpl.class);

	/**
	 * 阶段计价城市集合
	 */
	private static List<StagePriceCity> stagePriceCitys = null;

	/**
	 * 所有城市的计价规则集合
	 */
	private static Map<Integer, List<SpecialStageprice>> stagePriceMap = new HashMap<Integer, List<SpecialStageprice>>();

	@Resource(name = "stagePriceDao")
	private IStagePriceDao stagePriceDao; // 计价规则

	@Resource(name = "stagePriceCityDao")
	private IStagePriceCityDao stagePriceCityDao; // 计价规则城市

	@Resource(name = "criteriaBaseDao")
	private ICriteriaBaseDao criteriaBaseDao;

	/**
	 * 
	 * @Title: calculateDistance
	 * @Description:专车计算距离
	 * @author YHQ
	 * @since V2.4.0
	 * 
	 */
	@Override
	@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
	public String calculateDistance(String requestJson) {

		// 客户端请求参数
		ReqSpecialCalculateDistance reqSpecialCalculateDistance = super.parseRequestJson(requestJson);

		// 计算距离价格响应Bean
		ResponseEntity<ResSpecialCalculateDistance> response = new ResponseEntity<ResSpecialCalculateDistance>();

		// 1:验证请求参数
		if (!super.validateParam(response, reqSpecialCalculateDistance)) {
			return super.responseBeanToJson(response);
		}

		// 计算距离价格响应Bean
		ResSpecialCalculateDistance resSpecialCalculateDistance = new ResSpecialCalculateDistance();

		// 计算距离
		CalculatDistanceDTO calculatDistanceDTO = super.distance(reqSpecialCalculateDistance.getStartLongitude(),
				reqSpecialCalculateDistance.getStartLatitude(), reqSpecialCalculateDistance.getCurrentLongitude(),
				reqSpecialCalculateDistance.getCurrentLatitude());

		// 订单里程(订单里程保留一位小数)
		BigDecimal distance = calculatDistanceDTO.getDistance().setScale(1,BigDecimal.ROUND_UP);

		// 是否允许发单
		if (distance.compareTo(new BigDecimal(1)) < 0) {
			resSpecialCalculateDistance.setIsCondition(0);
		} else {
			resSpecialCalculateDistance.setIsCondition(1);
		}

		// 3:根据距离计算订单费用
		BigDecimal orderCost = calculatePrice(distance, calculatDistanceDTO.getCityNo());

		// 订单距离
		resSpecialCalculateDistance.setDistance(distance);

		if (orderCost == null) {
			orderCost = new BigDecimal(0);
		}

		// 订单费用
		resSpecialCalculateDistance.setTotalMoney(orderCost);

		response.setCode(HttpStatus.SC_OK);
		response.setResponseBody(resSpecialCalculateDistance);

		return super.responseBeanToJson(response);
	}

	/**
	 * 
	 * 费用计算
	 * 
	 * @Title: calculatePrice
	 * @param distance
	 *            订单里程
	 * @param stageprices
	 *            计价规则表数据集合
	 * @return Double 计算后的总金额，保留一位小数
	 * @author CHEHUANBO
	 * @version V2.4.0
	 * 
	 * 
	 */
	@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
	public BigDecimal calculatePrice(BigDecimal distance, int cityNo) {

		// 总金额
		BigDecimal totalMoney = new BigDecimal(0);
		// 获取所有的计价规则
		List<SpecialStageprice> stagePrices = this.getStageprices(cityNo);
		// 根据计价阶段进行升序排序
		Collections.sort(stagePrices);
		for (SpecialStageprice stageprice : stagePrices) {

			// 阶段
			int stage = stageprice.getStage();
			// 单价（元/公里）
			BigDecimal price = stageprice.getPrice();
			// 当前阶段的起始范围
			BigDecimal startRange = stageprice.getStartRange();
			// 当前阶段的结束范围
			BigDecimal endRange = stageprice.getEndRange();

			if (stage == 1) { // 第一阶段,起步阶段无需计算只要在规定的公里数内，直接使用起步价。
				totalMoney = totalMoney.add(stageprice.getPrice());
				continue;
			}

			if (distance.compareTo(startRange) > 0) { // 符合当前阶段的计算范围（除第一阶段）

				if (stage == stagePrices.size()) { // 最后一阶段，由于最后阶段没有结束范围，所以，剩余没有计算的距离直接按最后阶段单价计算
					totalMoney = totalMoney.add((distance.subtract(startRange)).multiply(price));
					break;
				} else if (distance.compareTo(endRange) < 0) { // 如果小于当前阶段的最大值，直接使用下单距离减去当前阶段起始距离
					totalMoney = totalMoney.add((distance.subtract(startRange)).multiply(price));
					break;
				} else if (distance.compareTo(endRange) > 0) { // 如果大于当前阶段的最大值，使用当前阶段的距离差计算，剩余订单距离继续进行后续计算
					totalMoney = totalMoney.add((endRange.subtract(startRange)).multiply(price));
					continue;
				}
			}
		}

		return totalMoney.setScale(1, BigDecimal.ROUND_UP);

	}

	/**
	 * 
	 * @Title: getStageprices
	 * @Description:获取全部计费规则
	 * @author CHEHUANBO
	 * @return List<Stageprice> 获取到的所有计费规则
	 * @since V2.4.0
	 * 
	 */
	@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
	protected synchronized List<SpecialStageprice> getStageprices(int cityNo) {

		// 根据城市编号获取计价规则
		List<SpecialStageprice> stagePrices = this.getStagePriceMap().get(cityNo);

		// 缓存中获取不到当前城市计费规则的时候，从数据库读取
		if (stagePrices == null) {
			// 验证计价城市是否存在，如果不存在使用其它
			boolean isExist = false;
			for (StagePriceCity stagePriceCity : getStagePriceCitys()) {
				int _cityNo = stagePriceCity.getCityNo();
				if (_cityNo == cityNo) {
					isExist = true;
				}
			}
			if (!isExist) {
				cityNo = -1; // 其它城市
			}

			try {
				Criterion criterion = Restrictions.and(Restrictions.eq("cityNo", cityNo), Restrictions.eq("status", 1));
				stagePrices = criteriaBaseDao.queryCriteriaList(SpecialStageprice.class, criterion);
			} catch (Exception e) {
				log.error("查询所有计价规则出现异常！", e);
			}
			stagePriceMap.put(cityNo, stagePrices);
		}

		return stagePrices;

	}

	public Map<Integer, List<SpecialStageprice>> getStagePriceMap() {
		return stagePriceMap;
	}

	@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
	public synchronized List<StagePriceCity> getStagePriceCitys() {

		if (stagePriceCitys == null) {
			stagePriceCitys = criteriaBaseDao.queryCriteriaList(StagePriceCity.class);
			if (stagePriceCitys == null) {
				stagePriceCitys = new ArrayList<StagePriceCity>();
			}
		}

		return stagePriceCitys;

	}

	@Override
	public BigDecimal calcDistanceCost(ReqCalculateDistanceDTO dto) {

		return null;
	}

}
